import gzip
import hashlib
import json
import os
import uuid
import zipfile
import zlib
from datetime import datetime
import xml.etree.ElementTree as ET
from io import BytesIO

import requests
from loguru import logger

from dto.ctrip_special_policy_request import *


# -*- coding: utf-8 -*-
# @Author : HJH
# @Time : 2024/1/23 10:19
# @Use : 携程上传特殊政策

def xc_process_row(row, pr_param):
    """
    定义一个函数，传入一行数据，转化为Policy需要导入的政策
    :param pr_param: 输入的参数
    :param row:携程数据
    :return:美团接口需要的Policy数据
    """
    if not isinstance(pr_param, dict):
        RuntimeError("输入参数有误，请检查后重新启动")

    is_share = 0
    if 'GX' in pr_param.get('platform', ''):
        is_share = 1

    # ******** 概要信息 ********
    summary = Summary()
    # 舱位等级
    summary.Class = 'Y'
    # 提前预订天数
    summary.AdvanceDay = pr_param.get('advanceDay')
    # 最大提前预订天数
    summary.MaxAdvanceDay = pr_param.get('maxAdvanceDay')
    # 政策代码
    summary.PolicyCode = pr_param.get('policyCode')
    # 根据仓位设置政策标识
    if pr_param.get('policy_of_cabin') == 1:
        if row.get('cabin') in 'N,T,Z,V,E,H,U,L,A,M,B,Y':
            summary.PolicyCode = (pr_param.get('policyCode') + '0')
        elif row.get('cabin') in 'R':
            summary.PolicyCode = (pr_param.get('policyCode') + '1')
    # 航空公司
    summary.AirLine = row.get('flightNo')[:2]
    # 航程类型
    summary.FlightWay = 'S'
    # 儿童是否适用
    summary.ApplyChild = 'F'
    # 授权Office号
    summary.OfficeNo = 'CGO104'
    # 始发机场代码
    summary.DepartPort = row.get('dep')
    # 到达机场代码
    summary.ArrivePort = row.get('arr')
    # 销售日期起
    summary.EffectDate = datetime.now().strftime("%Y-%m-%d")
    # 销售日期止
    summary.ExpiryDate = datetime.now().replace(month=12, day=31).strftime("%Y-%m-%d")
    # 政策是否有效
    summary.IsValid = 'T'
    # 产品类型
    summary.ProductType = pr_param.get('productMark')
    # 是否惠选
    summary.IsSecurity = 'F'
    # 是否申请
    summary.ApplyFlag = 'F'
    # 是否PATA
    summary.NeedPATA = 'F'
    # 出票备注
    summary.TicketRemark = row.get('price').split('.')[0] + pr_param.get('policy_note')
    # 是否自动出票
    summary.IsAutoTicket = 'F'
    # 是否共享航班
    summary.IsShareFlight = 'F' if is_share == 0 else 'T'
    # IATA号
    summary.IATANo = '08309722'
    # 共享航班是否对承运航司验证舱验价
    summary.IsValidCarrierAirline = 'F'
    # 退改规则id
    summary.RcID = '12278561'

    # ******** 库存信息 ********
    inventory = Inventory()
    # 库存查询模式
    inventory.InventoryType = 'FAV'
    # 是否订位
    inventory.IsBooking = pr_param.get('isBooking')
    # 紧张订位阈值
    inventory.BookingThreshold = pr_param.get('bookingThreshold')
    # 订位方式
    inventory.BookingType = '2'
    # 退票是否还库存
    inventory.IsReturnRefundInventory = 'F'
    # 是否紧张位置过滤
    inventory.IsShortageFilter = pr_param.get('isShortageFilter')
    # 紧张过滤阈值
    inventory.ShortageFilterCount = pr_param.get('shortageFilterCount', None)

    # ***** 航班信息 *****
    goFlightUnit = Flight()
    # 航班日期起
    goFlightUnit.EffectDate = row.get('depDate')
    # 航班日期止
    goFlightUnit.ExpiryDate = row.get('depDate')
    # 班期
    goFlightUnit.Days = '1234567'
    # 舱位
    goFlightUnit.SubClass = row.get('cabin')
    # 是否可售
    goFlightUnit.IsCanSale = 'T'
    # 航班号范围
    goFlightUnit.RuleDetail = row.get('flightNo')[2:]

    # ******** 价格信息 ********
    price = Price()
    # 票面价
    price.PrintPrice = str(int(float(row.get('costPrice'))) + pr_param.get('printPriceAdd', 0))
    # 留钱
    price.ReturnPrice = pr_param.get('returnPrice')
    # 代理费率
    price.ReturnPoint = pr_param.get('returnPoint')
    # 竞价空间
    price.BiddingSpace = pr_param.get('biddingSpace')
    # 竞价空间类型
    price.BidType = '0'

    # ******** 政策信息 ********
    policy = Policy()
    policy.SummaryUnit = summary
    policy.InventoryUnit = inventory
    policy.GoFlightUnit = goFlightUnit
    policy.PriceUnit = price
    return policy


def add_xc_policy(policies: list):
    """
    特殊政策新增上传参数
    :param policies: 政策列表
    :return:
    """
    # 公共请求
    root = ET.Element('SpecialPolicyAddRequest')
    root.set('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema')
    root.set('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance')
    root.set('xmlns', 'urn:ctrip:api:flight:trade:message:specialPolicy:v1')
    message_head_xml = ET.SubElement(root, 'MessageHead')
    request_GUID_xml = ET.SubElement(message_head_xml, 'RequestGUID')
    request_GUID_xml.text = str(uuid.uuid4())
    request_GUID_xml.set('xmlns', 'urn:ctrip:api:flight:trade:common:baseType:v1')
    # 用户信息
    user_info_xml = ET.SubElement(message_head_xml, 'UserInfo')
    user_info_xml.set('xmlns', 'urn:ctrip:api:flight:trade:common:baseType:v1')
    ET.SubElement(user_info_xml, 'UserName').text = 'yc001'
    ET.SubElement(user_info_xml, 'Password').text = hashlib.md5(
        "yc001#dahedianli@22.".encode('utf-8')).hexdigest().upper()
    # 业务参数体
    message_body_xml = ET.SubElement(root, 'MessageBody')
    policy_list_xml = ET.SubElement(message_body_xml, 'PolicyList')
    for policy in policies:
        policy_xml = ET.SubElement(policy_list_xml, 'Policy')
        summary_unit_xml = ET.SubElement(policy_xml, 'SummaryUnit')
        for key, value in vars(policy.SummaryUnit).items():
            ET.SubElement(summary_unit_xml, key).text = value
        inventory_unit_xml = ET.SubElement(policy_xml, 'InventoryUnit')
        for key, value in vars(policy.InventoryUnit).items():
            ET.SubElement(inventory_unit_xml, key).text = value
        go_flight_unit_xml = ET.SubElement(policy_xml, 'GoFlightUnit')
        for key, value in vars(policy.GoFlightUnit).items():
            ET.SubElement(go_flight_unit_xml, key).text = value
        price_unit_xml = ET.SubElement(policy_xml, 'PriceUnit')
        for key, value in vars(policy.PriceUnit).items():
            ET.SubElement(price_unit_xml, key).text = value

    xml_data = ET.tostring(root, encoding='utf-8', xml_declaration=True).decode('utf-8')
    # print(xml_data)
    return xml_data


def del_xc_policy(del_p_c, is_fuzzy_match):
    """
    单程统一政策删除参数
    :param is_fuzzy_match: 是否模糊匹配	T-是 F-否
    :param del_p_c: 需要删除政策代码
    :return:
    """
    # 公共请求
    root = ET.Element('SpecialPolicyAddRequest')
    root.set('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema')
    root.set('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance')
    root.set('xmlns', 'urn:ctrip:api:flight:trade:message:specialPolicy:v1')
    message_head_xml = ET.SubElement(root, 'MessageHead')
    request_GUID_xml = ET.SubElement(message_head_xml, 'RequestGUID')
    request_GUID_xml.text = str(uuid.uuid4())
    request_GUID_xml.set('xmlns', 'urn:ctrip:api:flight:trade:common:baseType:v1')
    # 用户信息
    user_info_xml = ET.SubElement(message_head_xml, 'UserInfo')
    user_info_xml.set('xmlns', 'urn:ctrip:api:flight:trade:common:baseType:v1')
    ET.SubElement(user_info_xml, 'UserName').text = 'yc001'
    ET.SubElement(user_info_xml, 'Password').text = hashlib.md5(
        "yc001#dahedianli@22.".encode('utf-8')).hexdigest().upper()

    message_body_xml = ET.SubElement(root, 'MessageBody')
    ET.SubElement(message_body_xml, 'DeleteType').text = 'ByCode'
    policy_codeList_xml = ET.SubElement(message_body_xml, 'PolicyCodeList')
    ET.SubElement(policy_codeList_xml, 'Code').text = del_p_c
    ET.SubElement(message_body_xml, 'PolicySource').text = 'All'
    ET.SubElement(message_body_xml, 'IsFuzzyMatch').text = is_fuzzy_match

    xml_data = ET.tostring(root, encoding='utf-8', xml_declaration=True).decode('utf-8')
    # print(xml_data)
    return xml_data


def send_xc_request(xml_params, url_path):
    headers = {
        "Content-Encoding": "gzip"
    }
    url = f"http://exchdata.ctrip.com/Flight-Proxy-TradeQuickAPI/api/xml/{url_path}"
    response = requests.post(url, headers=headers, data=gzip.compress(xml_params.encode('utf-8')))

    logger.info("【携程请求结果】: {}", response.text)
    if response.status_code != 200:
        logger.error("【携程请求异常】: {}", response.content)


def run_xc_upload(ru_data_res, ru_param):
    if not isinstance(ru_param, dict):
        RuntimeError("输入参数有误，请检查后重新启动")

    policyDtoList = []
    for item in ru_data_res:
        # 根据舱位复制
        if ru_param.get('copy_of_cabin', None) is not None:
            cabins = ru_param.get('copy_of_cabin').split(',')
            for cabin in cabins:
                item['cabin'] = cabin
                policyDto = xc_process_row(item, ru_param)
                policyDtoList.append(policyDto)
        else:
            policyDto = xc_process_row(item, ru_param)
            policyDtoList.append(policyDto)

    size = 10000
    total = len(policyDtoList)
    logger.info(f"【上传{ru_param.get('platform')}政策数据长度】: {total}")
    if total == 0:
        return
    logger.info(f"【携程特殊政策新增上传】: 请求中... ...")
    for i in range(0, total, size):
        # 取出最大10000条数据，添加到结果列表
        end = i + size
        subset = policyDtoList[i:end]
        # 获取请求参数
        add_req = add_xc_policy(subset)
        send_xc_request(add_req, 'SpecialPolicyAdd')

    logger.info(f"【携程特殊政策新增上传成功】: {ru_param.get('policyCode')}")